import org.acegisecurity.context.SecurityContextHolder as SCH
import org.springframework.util.StringUtils as STU
import org.apache.commons.codec.digest.DigestUtils as DU

import org.acegisecurity.GrantedAuthorityImpl

class AuthenticationHelperService {

    boolean transactional = true
    def acegiConfig = null

    def ifAllGranted(roles) {
        def granted = getPrincipalAuthorities()
        if (!granted.containsAll(parseAuthoritiesString(role))) {
            return false
        } else {
            return true
        }
    }

    def ifNotGranted(roles) {
        def granted = getPrincipalAuthorities()
        Set grantedCopy = retainAll(granted, parseAuthoritiesString(role));
        if (!grantedCopy.isEmpty()) {
            return false
        } else {
            return true
        }
    }

    def ifAnyGranted(role) {
        def granted = getPrincipalAuthorities()
        Set grantedCopy = retainAll(granted, parseAuthoritiesString(role));
        if (grantedCopy.isEmpty()) {
            return false
        } else {
            return true
        }
    }

    def authoritiesToRoles(def c) {
        Set target = new HashSet()
        c.each {authority ->
            if (null == authority.getAuthority()) {
                throw new IllegalArgumentException(
                        "Cannot process GrantedAuthority objects which return null from getAuthority() - attempting to process "
                                + authority)
            }
            target.add(authority.authority)
        }
        return target;
    }

    def getPrincipalAuthorities() {
        def currentUser = SCH.context.authentication
        if (null == currentUser) {
            return Collections.EMPTY_LIST;
        }
        if ((null == currentUser.authorities) || (currentUser.authorities.length < 1)) {
            return Collections.EMPTY_LIST;
        }
        def granted = Arrays.asList(currentUser.authorities);

        return granted;
    }

    def parseAuthoritiesString(def authorizationsString) {
        def requiredAuthorities = new HashSet()
        def authorities = STU.commaDelimitedListToStringArray(authorizationsString)
        authorities.each {auth ->
            requiredAuthorities.add(new GrantedAuthorityImpl(auth))
        }
        return requiredAuthorities
    }

    def retainAll(def granted, def required) {
        def grantedRoles = authoritiesToRoles(granted);
        def requiredRoles = authoritiesToRoles(required);
        grantedRoles.retainAll(requiredRoles);

        return rolesToAuthorities(grantedRoles, granted);
    }

    def rolesToAuthorities(def grantedRoles, def granted) {
        def target = new HashSet()
        grantedRoles.each {role ->
            def auth = granted.find {authority -> authority.authority == role}
            if (auth != null) {
                target.add(auth.authority)
            }
        }
        return target;
    }

    def getPrincipal() {
        return SCH?.context?.authentication?.principal
    }

    def userDomain() {
        def principal = getPrincipal()
        def loginUser = null
        if (principal != null && principal != "anonymousUser") {
            loginUser = principal?.domainClass
        }
        return loginUser
    }

    def getAcegiConfig() {
        if (this.acegiConfig == null) {
            ClassLoader parent = getClass().getClassLoader()
            GroovyClassLoader loader = new GroovyClassLoader(parent)
            def ac = loader.loadClass("AcegiConfig")
            def dac = loader.loadClass("DefaultAcegiConfig")
            def _user_config = new ConfigSlurper().parse(ac)
            def _default_config = new ConfigSlurper().parse(dac)
            this.acegiConfig = _default_config.merge(_user_config)
        }
        return this.acegiConfig
    }

    def passwordEncoder(String passwd) {
        def acegiConfig = getAcegiConfig()

        def algorithm = acegiConfig.acegi.algorithm
        def encodeHashAsBase64 = acegiConfig.acegi.encodeHashAsBase64
        def algorithmMethod = acegiConfig.algorithmMethods."${algorithm}"
        def pazzwd

        if (encodeHashAsBase64) {
            pazzwd = DU."${algorithmMethod}"(passwd).getBytes().encodeBase64()
        } else {
            pazzwd = DU."${algorithmMethod}"(passwd)
        }
        return pazzwd
    }
}